package com.iot08.api.service;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.utils.StringUtils;
import com.iot08.api.config.redis.RedisClusterService;
import com.iot08.api.dto.res.DrinkDataRes;
import com.iot08.api.service.supplement.KafkaService;
import com.iot08.api.utils.TimeUtils;
import com.iot08.api.vo.request.HealthRemindQueryReqVo;
import com.iot08.api.vo.request.HealthRemindReqVo;
import com.iot08.common.constant.ConstCacheField;
import com.iot08.common.constant.ConstKafka;
import com.iot08.common.entity.app.HealthRemind;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * @author cwj
 * @description
 * @date 2024/11/11 9:36
 **/
@Slf4j
@Service
public class HealthRemindService extends BaseService<HealthRemind> {

    @Resource
    private KafkaService kafkaService;

    @Resource
    private RedisClusterService redisClusterService;

    @Resource
    private DrinkDataService drinkDataService;
    
    
    /***
     * @description 查询健康
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/11/13 10:45
     **/
    public ResponseMap queryHealthRemind(String imei, HealthRemindQueryReqVo vo){
        ResponseMap res = ResponseMap.success();
        Date date = new Date();
        String todayStr = DateUtil.dateToStr(date, "yyyy-MM-dd");
        Criteria criteria = Criteria.where("imei").is(imei).and("type").is(vo.getType()).and("date").is(todayStr);
        Query query = (new Query(criteria)).limit(1);
        HealthRemind healthRemind = this.findOne(query);
        if (ObjectUtils.isEmpty(healthRemind)) {
            criteria = Criteria.where("imei").is(imei).and("type").is(vo.getType());
            query = (new Query(criteria)).with(Sort.by(new Sort.Order[]{Sort.Order.desc("date")})).limit(1);
            healthRemind = this.findOne(query);
        }
        JSONObject data = new JSONObject();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        if(!ObjectUtils.isEmpty(healthRemind)){
            this.settingHealthReaminData(imei, healthRemind, data, formatter);
            if ("2".equals(vo.getType())) {
                this.queryDrinkData(imei, formatter, data, healthRemind.getTarget());
            }
        }
        res.put("data", data);
        return res;
    }

    /**
     * @description 查询喝水提醒的数据
     * @author cwj
     * @param [imei, formatter, data, target]
     * @return void
     * @date @time 2024/12/2 14:58
     **/
    private void queryDrinkData(String imei, DateTimeFormatter formatter, JSONObject data, Integer target) {
        JSONObject drinkDataJson = new JSONObject();
        List<DrinkDataRes> drinkDatas = this.drinkDataService.queryTodayDrinkDataRes(imei);
        int totalLitre = 0;
        for (DrinkDataRes drinkData : drinkDatas) {
            totalLitre += drinkData.getDrinkLitre();
            LocalDateTime ldt = (new Date(drinkData.getReportTime())).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            drinkData.setReportTimeStr(ldt.format(formatter));
        }

        int surplusLitre = target - totalLitre;
        float rate = (float)totalLitre / (float)target;
        if (surplusLitre < 0) {
            surplusLitre = 0;
            rate = 1.0F;
        }

        BigDecimal litreRate = (BigDecimal.valueOf((rate * 100.0F))).setScale(1, RoundingMode.HALF_UP);
        drinkDataJson.put("totalLitre", totalLitre);
        drinkDataJson.put("surplusLitre", surplusLitre);
        drinkDataJson.put("litreRate", litreRate + "%");
        drinkDataJson.put("drinkRecord", drinkDatas);
        data.put("drinkData", drinkDataJson);
    }
    
    /**
     * @description 设置健康提醒的对象数据
     * @author cwj
     * @param [imei, healthRemind, data, formatter]
     * @return void
     * @date @time 2024/12/2 14:57
     **/
    private void settingHealthReaminData(String imei, HealthRemind healthRemind, JSONObject data, DateTimeFormatter formatter) {
        LocalDateTime localDateTime = healthRemind.getUpdateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        data.put("imei", imei);
        data.put("type", healthRemind.getType());
        data.put("isOpen", healthRemind.getIsOpen());
        data.put("interval", healthRemind.getInterval());
        data.put("starTime", healthRemind.getStarTime());
        data.put("endTime", healthRemind.getEndTime());
        data.put("isNoonDnd", healthRemind.getIsNoonDnd());
        data.put("dndstartTime", healthRemind.getDndstartTime());
        data.put("dndEndTime", healthRemind.getDndEndTime());
        data.put("repStr", healthRemind.getRepStr());
        data.put("target", healthRemind.getTarget());
        data.put("updateTime", localDateTime.format(formatter));
    }



    /**
     * @description 设置健康提醒功能（1：喝水提醒，2：久坐提醒）
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/11/11 14:15
     **/
    public ResponseMap settingHealthRemind(String imei, HealthRemindReqVo vo){
        String regex = "^([01]?[0-9]|2[0-3]):[0-5][0-9]$";
        //检查参数是否正确
        ResponseMap responseMap = checkParam(vo, regex);
        if (responseMap != null) return responseMap;
        //检查设备是否在线
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        //设置默认的午休免打扰时间值
        settingDefaultDnsTime(vo);
        //检查设备今日有无发送相同的健康指令，保持相同指令每天在数据表中只存一条
        Date date = new Date();
        String todayStr = DateUtil.dateToStr(date, DateUtil.FORMAT_4);
        HealthRemind healthRemind = queryCurrentHealthRemind(imei, vo, todayStr);
        if(ObjectUtils.isEmpty(healthRemind)){
            healthRemind = assembleHealthRemind(imei, vo, todayStr, date);
            this.save(healthRemind);
        }else{
            Update update = assembleHealthReminUpdate(vo, todayStr, healthRemind, date);
            this.updateById(healthRemind.getId(),update);
        }
        JSONObject kafkaJson = assembleKafkaJsonObject(vo);
        //发送健康提醒功能（喝水提醒，久坐提醒）设置的指令
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_HEALTH_REMIND, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * @description 组装推送kafka的请求参数
     * @author cwj
     * @param [vo]
     * @return com.alibaba.fastjson.JSONObject
     * @date @time 2024/11/11 16:48
     **/
    private JSONObject assembleKafkaJsonObject(HealthRemindReqVo vo) {
        JSONObject kafkaJson = new JSONObject();
        Integer defaultTarget = this.setDefaultTarget(vo.getType());
        kafkaJson.put("healthRemindType", vo.getType());
        kafkaJson.put("isopen", vo.getIsOpen());
        kafkaJson.put("interval", vo.getInterval());
        kafkaJson.put("stratTime", vo.getStarTime());
        kafkaJson.put("endTime", vo.getEndTime());
        kafkaJson.put("isNoonDnd", vo.getIsNoonDnd());
        kafkaJson.put("dndstartTime", vo.getDndstartTime());
        kafkaJson.put("dndEndTime", vo.getDndEndTime());
        kafkaJson.put("repStr", vo.getRepStr());
        kafkaJson.put("target",ObjectUtils.isEmpty(vo.getTarget())?defaultTarget: vo.getTarget());
        return kafkaJson;
    }

    private Integer setDefaultTarget(String type) {
        short defaultTarget;
        if (type.equals("1")) {
            defaultTarget = 1500;
        } else {
            defaultTarget = 0;
        }

        return Integer.valueOf(defaultTarget);
    }

    /**
     * @description 组装更新HealthRemind的Update对象
     * @author cwj
     * @param [vo, todayStr, healthRemind, date]
     * @return org.springframework.data.mongodb.core.query.Update
     * @date @time 2024/11/11 16:33
     **/
    private Update assembleHealthReminUpdate(HealthRemindReqVo vo, String todayStr, HealthRemind healthRemind, Date date) {
        Update update = new Update();
        Integer defaultTarget = this.setDefaultTarget(vo.getType());
        update.set("date", todayStr);
        update.set("openId", vo.getOpenid());
        update.set("interval", vo.getInterval());
        update.set("updateTime", date);
        update.set("type", vo.getType());
        update.set("target",ObjectUtils.isEmpty(vo.getTarget())?defaultTarget : vo.getTarget());
        update.set("isOpen", vo.getIsOpen());
        update.set("isNoonDnd", vo.getIsNoonDnd());
        update.set("repStr", vo.getRepStr());
        update.set("starTime", vo.getStarTime());
        update.set("endTime", vo.getEndTime());
        update.set("dndstartTime", vo.getDndstartTime());
        update.set("dndEndTime", vo.getDndEndTime());
        return update;
    }

    /**
     * @description 组装HealthRemind对象
     * @author cwj
     * @param [imei, vo, todayStr, date]
     * @return com.iot08.common.entity.app.HealthRemind
     * @date @time 2024/11/11 16:21
     **/
    private HealthRemind assembleHealthRemind(String imei, HealthRemindReqVo vo, String todayStr, Date date) {
        Integer defaultTarget = this.setDefaultTarget(vo.getType());
        HealthRemind healthRemind = new HealthRemind();
        healthRemind.setDate(todayStr);
        healthRemind.setImei(imei);
        healthRemind.setOpenId(vo.getOpenid());
        healthRemind.setCreateTime(date);
        healthRemind.setInterval(vo.getInterval());
        healthRemind.setUpdateTime(date);
        healthRemind.setType(vo.getType());
        healthRemind.setTarget(ObjectUtils.isEmpty(vo.getTarget())? defaultTarget : vo.getTarget());
        healthRemind.setIsOpen(vo.getIsOpen());
        healthRemind.setIsNoonDnd(vo.getIsNoonDnd());
        healthRemind.setRepStr(vo.getRepStr());
        healthRemind.setStarTime(vo.getStarTime());
        healthRemind.setEndTime(vo.getEndTime());
        healthRemind.setDndstartTime(vo.getDndstartTime());
        healthRemind.setDndEndTime(vo.getDndEndTime());
        return healthRemind;
    }

    /**
     * @description 查询健康提醒功能当天的指令信息
     * @author cwj
     * @param [imei, vo, todayStr]
     * @return com.iot08.common.entity.app.HealthRemind
     * @date @time 2024/11/11 16:04
     **/
    public HealthRemind queryCurrentHealthRemind(String imei, HealthRemindReqVo vo, String date) {
        Query query = new Query(Criteria.where("imei").is(imei).and("type").is(vo.getType()).and("date").is(date));
        return this.findOne(query);
    }

    /**
     * @description 设置默认的午休免打扰时间值
     * @author cwj
     * @param [vo]
     * @return void
     * @date @time 2024/11/11 15:29
     **/
    private void settingDefaultDnsTime(HealthRemindReqVo vo) {
        if(StringUtils.isEmpty(vo.getStarTime()) || StringUtils.isEmpty(vo.getStarTime())){
            vo.setDndstartTime("12:00");
            vo.setDndEndTime("14:00");
        }
    }

    /**
     * @description 检查午休免打扰时间参数是否设置正确、健康检查的时间参数
     * @author cwj
     * @param [vo, regex]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/11/11 15:26
     **/
    private ResponseMap checkParam(HealthRemindReqVo vo, String regex) {
        if("2".equals(vo.getType()) && vo.getTarget() <= 0){
            return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.target");
        }
        if(!TimeUtils.compareHourMin(vo.getStarTime(), vo.getEndTime())) {
            return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.startEndTime");
        }
        if("1".equals(vo.getIsNoonDnd())){
            if(StringUtils.isEmpty(vo.getDndstartTime()) || !vo.getDndstartTime().matches(regex)){
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.lunchtime.start");
            }
            if(StringUtils.isEmpty(vo.getDndEndTime()) || !vo.getDndEndTime().matches(regex)){
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.lunchtime.end");
            }
        }else{
            if(!StringUtils.isEmpty(vo.getDndstartTime()) && !vo.getDndstartTime().matches(regex)){
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.start");
            }
            if(!StringUtils.isEmpty(vo.getDndEndTime()) && !vo.getDndEndTime().matches(regex)){
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.end");
            }
        }
        if (!StringUtils.isEmpty(vo.getDndstartTime()) && !StringUtils.isEmpty(vo.getDndEndTime()) && !TimeUtils.compareHourMin(vo.getDndstartTime(), vo.getDndEndTime())) {
            return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "API.request.parameterError.healthRemind.lunchtime.startEndTime");
        }
        return null;
    }
}
